import React from "react";
import 'antd/dist/antd.css';
import Phaser, {Game} from "phaser";

const json = {
    'sky': 'assets/sky.png',
    'star': 'assets/star.png',
    'ground': 'assets/platform.png',
    'bomb': 'assets/bomb.png',
    'boom': 'assets/boom.png',
    'over': 'assets/over.png'
};

function Main() {
    window.game = new Game({
        type: Phaser.AUTO,
        width: 800,
        height: 600,
        parent: 'game',
        physics: {
            default: 'arcade',
            arcade: {
                gravity: {y: 300},
                debug: false
            }
        },
        scene: {
            preload: preload,
            create: create,
            update: update
        }
    });

    return (
        <div id='game'/>
    )
}

// 预加载
function preload() {
    // 图片
    Object.keys(json).forEach((key) => {
        this.load.image(key, `${json[key]}`)
    });
    // 精灵图
    this.load.spritesheet('dude',
        'assets/dude.png',
        {frameWidth: 32, frameHeight: 48}
    );
    this.load.spritesheet('dude2',
        'assets/dude2.png',
        {frameWidth: 32, frameHeight: 48}
    );
}

// 平台
let platforms;
// 人物
let player;
let player2;
let stars;
let time = 200;
let timeText;
let timer;
let score = 0;
let score2 = 0;
let scoreText;
let scoreText2;
let bombs;
let gameOver;
let gameOver2;

// 加载资源
function create() {
    // 设置背景
    this.add.image(400, 300, 'sky');

    // 使用物理引擎，生成一个静态物理组，只有位置和尺寸
    platforms = this.physics.add.staticGroup();
    // 地板
    // 用函数 setScale(2) 把它按x2（两倍）缩放
    // 调用 refreshBody()，把变动告诉物理引擎
    platforms.create(400, 568, 'ground').setScale(2).refreshBody();
    // 台阶
    platforms.create(600, 400, 'ground');
    platforms.create(50, 250, 'ground');
    platforms.create(750, 220, 'ground');

    // 配置人物，动态物理，有速度速度、加速度等，跟其他对象发生反弹、碰撞等。
    player = this.physics.add.sprite(559, 450, 'dude');
    player2 = this.physics.add.sprite(100, 450, 'dude2');

    // 配置反弹值
    // player.setBounce(0.2);
    // player2.setBounce(0.2);
    // 设置边界，使得人物无法抛出边界
    player.setCollideWorldBounds(true);
    player2.setCollideWorldBounds(true);

    // 为人物和平台设置物理碰撞
    this.physics.add.collider(player, platforms);
    this.physics.add.collider(player2, platforms);
    this.physics.add.collider(player, player2);

    // 动画创建
    this.anims.create({
        key: 'left',
        frames: this.anims.generateFrameNumbers('dude', {start: 0, end: 3}),
        frameRate: 10,
        repeat: -1
    });
    this.anims.create({
        key: 'turn',
        frames: [{key: 'dude', frame: 4}],
        frameRate: 20
    });
    this.anims.create({
        key: 'right',
        frames: this.anims.generateFrameNumbers('dude', {start: 5, end: 8}),
        frameRate: 10,
        repeat: -1
    });

    // 动画创建
    this.anims.create({
        key: 'left2',
        frames: this.anims.generateFrameNumbers('dude2', {start: 0, end: 3}),
        frameRate: 10,
        repeat: -1
    });
    this.anims.create({
        key: 'turn2',
        frames: [{key: 'dude2', frame: 4}],
        frameRate: 20
    });
    this.anims.create({
        key: 'right2',
        frames: this.anims.generateFrameNumbers('dude2', {start: 5, end: 8}),
        frameRate: 10,
        repeat: -1
    });

    // 星星道具配置
    // key 指定的图片
    // repeat 设置重复值 11 ，加上自身一个 12 个
    // setXY 设置位置：x y 表示初始值 14 0 , stepX 表示水平方向的递进距离
    stars = this.physics.add.group({
        key: 'star',
        repeat: 11,
        setXY: {x: 14, y: 0, stepX: 70}
    });

    // 随机设置垂直反弹值 0.4 ~ 0.8
    stars.children.iterate((child) => {
        child.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
    });

    // 为星星配置物理碰撞
    this.physics.add.collider(stars, platforms);
    // 判断两个实体是否重叠，重叠执行 collectStar 函数
    this.physics.add.overlap(player, stars, collectStar, null, this);
    this.physics.add.overlap(player2, stars, collectStar2, null, this);

    // 分数及时间
    scoreText = this.add.text(
        608, 16,
        'Score: ' + score,
        { fontSize: '28px', fill: '#5571a9' });
    scoreText2 = this.add.text(
        16, 16,
        'Score: ' + score,
        { fontSize: '28px', fill: '#5571a9' });
    timeText = this.add.text(
        310, 16,
        'Time: ' + time,
        { font: "28px", fill: "#5571a9", align: "center" });

    // 倒计时
    timer = setInterval(() => {
        time = time - 1;
        timeText.text = 'Time: ' + time;
        if (time === 0) {
            this.physics.pause();
            this.add.text(
                290, 300,
                'Game Over',
                { font: "40px", fill: "#ff3d27"});
            clearInterval(timer);
        }
    }, 1000);

    // 添加炸单，当星星被吃完时
    bombs = this.physics.add.group();

    // 为炸单添加与平台的物理碰撞
    this.physics.add.collider(bombs, platforms);
    this.physics.add.overlap(player, bombs, hitBomb, null, this);
    this.physics.add.overlap(player2, bombs, hitBomb2, null, this);
}

function collectStar(player, star) {
    score += 10;
    scoreText.setText('Score: ' + score);
    collectStarConfig(player, star);
}

function collectStar2(player, star) {
    score2 += 10;
    scoreText2.setText('Score: ' + score2);
    collectStarConfig(player, star);
}

function collectStarConfig(player, star) {
    star.disableBody(true, true);
    // 判断是否存在星星
    if (stars.countActive(true) === 0) {
        // 重新激活所有星星
        stars.children.iterate((child) => {
            child.enableBody(true, child.x, 0, true, true);
        });

        let x = (player.x < 400)
            ? Phaser.Math.Between(400, 800)
            : Phaser.Math.Between(0, 400);

        let bomb = bombs.create(x, 16, 'bomb');
        bomb.setBounce(1);
        bomb.setCollideWorldBounds(true);
        bomb.setVelocity(Phaser.Math.Between(-200, 200), 20);
    }
}

function hitBomb (player, bomb) {
    // 消除人物 炸单
    player.disableBody(true, true);
    bomb.disableBody(true, true);

    this.add.sprite(player.x, player.y , 'boom').setDisplaySize(80, 80);

    player.setTint(0xff0000);
    player.anims.play('turn');

    gameOver = true;
    if (gameOver && gameOver2) {
        // 停止游戏
        this.physics.pause();
        this.add.text(
            290, 300,
            'Game Over',
            { font: "40px", fill: "#ff3d27"});
        clearInterval(timer);
    }
}

function hitBomb2 (player, bomb) {
    // 消除人物 炸单
    player.disableBody(true, true);
    bomb.disableBody(true, true);

    this.add.sprite(player.x, player.y , 'boom').setDisplaySize(80, 80);

    player.setTint(0xff0000);
    player.anims.play('turn');

    gameOver2 = true;
    if (gameOver && gameOver2) {
        this.physics.pause();
        this.add.text(
            290, 300,
            'Game Over',
            { font: "40px", fill: "#ff3d27"});
        clearInterval(timer);
    }
}

let cursors;
let cursors2;

function update() {
    cursors = this.input.keyboard.createCursorKeys();
    cursors2 = this.input.keyboard.addKeys({
        'left': Phaser.Input.Keyboard.KeyCodes.A,
        'right': Phaser.Input.Keyboard.KeyCodes.D,
        'up': Phaser.Input.Keyboard.KeyCodes.W
    });

    keyConfig(cursors, player);
    keyConfig2(cursors2, player2);
}

/**
 * 为键盘事件赋予动画，并应用到人物中
 * @param cursors 键盘
 * @param player 人物
 */
function keyConfig(cursors, player) {
    if (cursors.left.isDown) {
        // 配置水平速度
        player.setVelocityX(-160);
        // 执行动画
        player.anims.play('left', true);
    } else if (cursors.right.isDown) {
        player.setVelocityX(160);
        player.anims.play('right', true);
    } else {
        player.setVelocityX(0);
        player.anims.play('turn');
    }
    if (cursors.up.isDown && player.body.touching.down) {
        // 配置垂直速度
        player.setVelocityY(-330);
    }
}

/**
 * 为键盘事件赋予动画，并应用到人物中
 * @param cursors 键盘
 * @param player 人物
 */
function keyConfig2(cursors, player) {
    if (cursors.left.isDown) {
        // 配置水平速度
        player.setVelocityX(-160);
        // 执行动画
        player.anims.play('left2', true);
    } else if (cursors.right.isDown) {
        player.setVelocityX(160);
        player.anims.play('right2', true);
    } else {
        player.setVelocityX(0);
        player.anims.play('turn2');
    }
    if (cursors.up.isDown && player.body.touching.down) {
        // 配置垂直速度
        player.setVelocityY(-330);
    }
}

export default Main;
